export default function (module, exports, __webpack_require__) {

    var matrix = __webpack_require__("1687");

    var vector = __webpack_require__("401b");

    /**
     * 提供变换扩展
     * @module zrender/mixin/Transformable
     * @author pissang (https://www.github.com/pissang)
     */
    var mIdentity = matrix.identity;
    var EPSILON = 5e-5;

    function isNotAroundZero(val) {
        return val > EPSILON || val < -EPSILON;
    }
    /**
     * @alias module:zrender/mixin/Transformable
     * @constructor
     */


    var Transformable = function (opts) {
        opts = opts || {}; // If there are no given position, rotation, scale

        if (!opts.position) {
            /**
             * 平移
             * @type {Array.<number>}
             * @default [0, 0]
             */
            this.position = [0, 0];
        }

        if (opts.rotation == null) {
            /**
             * 旋转
             * @type {Array.<number>}
             * @default 0
             */
            this.rotation = 0;
        }

        if (!opts.scale) {
            /**
             * 缩放
             * @type {Array.<number>}
             * @default [1, 1]
             */
            this.scale = [1, 1];
        }
        /**
         * 旋转和缩放的原点
         * @type {Array.<number>}
         * @default null
         */


        this.origin = this.origin || null;
    };

    var transformableProto = Transformable.prototype;
    transformableProto.transform = null;
    /**
     * 判断是否需要有坐标变换
     * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵
     */

    transformableProto.needLocalTransform = function () {
        return isNotAroundZero(this.rotation) || isNotAroundZero(this.position[0]) || isNotAroundZero(this.position[1]) || isNotAroundZero(this.scale[0] - 1) || isNotAroundZero(this.scale[1] - 1);
    };

    var scaleTmp = [];

    transformableProto.updateTransform = function () {
        var parent = this.parent;
        var parentHasTransform = parent && parent.transform;
        var needLocalTransform = this.needLocalTransform();
        var m = this.transform;

        if (!(needLocalTransform || parentHasTransform)) {
            m && mIdentity(m);
            return;
        }

        m = m || matrix.create();

        if (needLocalTransform) {
            this.getLocalTransform(m);
        } else {
            mIdentity(m);
        } // 应用父节点变换


        if (parentHasTransform) {
            if (needLocalTransform) {
                matrix.mul(m, parent.transform, m);
            } else {
                matrix.copy(m, parent.transform);
            }
        } // 保存这个变换矩阵


        this.transform = m;
        var globalScaleRatio = this.globalScaleRatio;

        if (globalScaleRatio != null && globalScaleRatio !== 1) {
            this.getGlobalScale(scaleTmp);
            var relX = scaleTmp[0] < 0 ? -1 : 1;
            var relY = scaleTmp[1] < 0 ? -1 : 1;
            var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;
            var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;
            m[0] *= sx;
            m[1] *= sx;
            m[2] *= sy;
            m[3] *= sy;
        }

        this.invTransform = this.invTransform || matrix.create();
        matrix.invert(this.invTransform, m);
    };

    transformableProto.getLocalTransform = function (m) {
        return Transformable.getLocalTransform(this, m);
    };
    /**
     * 将自己的transform应用到context上
     * @param {CanvasRenderingContext2D} ctx
     */


    transformableProto.setTransform = function (ctx) {
        var m = this.transform;
        var dpr = ctx.dpr || 1;

        if (m) {
            ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);
        } else {
            ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
        }
    };

    transformableProto.restoreTransform = function (ctx) {
        var dpr = ctx.dpr || 1;
        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };

    var tmpTransform = [];
    var originTransform = matrix.create();

    transformableProto.setLocalTransform = function (m) {
        if (!m) {
            // TODO return or set identity?
            return;
        }

        var sx = m[0] * m[0] + m[1] * m[1];
        var sy = m[2] * m[2] + m[3] * m[3];
        var position = this.position;
        var scale = this.scale;

        if (isNotAroundZero(sx - 1)) {
            sx = Math.sqrt(sx);
        }

        if (isNotAroundZero(sy - 1)) {
            sy = Math.sqrt(sy);
        }

        if (m[0] < 0) {
            sx = -sx;
        }

        if (m[3] < 0) {
            sy = -sy;
        }

        position[0] = m[4];
        position[1] = m[5];
        scale[0] = sx;
        scale[1] = sy;
        this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);
    };
    /**
     * 分解`transform`矩阵到`position`, `rotation`, `scale`
     */


    transformableProto.decomposeTransform = function () {
        if (!this.transform) {
            return;
        }

        var parent = this.parent;
        var m = this.transform;

        if (parent && parent.transform) {
            // Get local transform and decompose them to position, scale, rotation
            matrix.mul(tmpTransform, parent.invTransform, m);
            m = tmpTransform;
        }

        var origin = this.origin;

        if (origin && (origin[0] || origin[1])) {
            originTransform[4] = origin[0];
            originTransform[5] = origin[1];
            matrix.mul(tmpTransform, m, originTransform);
            tmpTransform[4] -= origin[0];
            tmpTransform[5] -= origin[1];
            m = tmpTransform;
        }

        this.setLocalTransform(m);
    };
    /**
     * Get global scale
     * @return {Array.<number>}
     */


    transformableProto.getGlobalScale = function (out) {
        var m = this.transform;
        out = out || [];

        if (!m) {
            out[0] = 1;
            out[1] = 1;
            return out;
        }

        out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);
        out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);

        if (m[0] < 0) {
            out[0] = -out[0];
        }

        if (m[3] < 0) {
            out[1] = -out[1];
        }

        return out;
    };
    /**
     * 变换坐标位置到 shape 的局部坐标空间
     * @method
     * @param {number} x
     * @param {number} y
     * @return {Array.<number>}
     */


    transformableProto.transformCoordToLocal = function (x, y) {
        var v2 = [x, y];
        var invTransform = this.invTransform;

        if (invTransform) {
            vector.applyTransform(v2, v2, invTransform);
        }

        return v2;
    };
    /**
     * 变换局部坐标位置到全局坐标空间
     * @method
     * @param {number} x
     * @param {number} y
     * @return {Array.<number>}
     */


    transformableProto.transformCoordToGlobal = function (x, y) {
        var v2 = [x, y];
        var transform = this.transform;

        if (transform) {
            vector.applyTransform(v2, v2, transform);
        }

        return v2;
    };
    /**
     * @static
     * @param {Object} target
     * @param {Array.<number>} target.origin
     * @param {number} target.rotation
     * @param {Array.<number>} target.position
     * @param {Array.<number>} [m]
     */


    Transformable.getLocalTransform = function (target, m) {
        m = m || [];
        mIdentity(m);
        var origin = target.origin;
        var scale = target.scale || [1, 1];
        var rotation = target.rotation || 0;
        var position = target.position || [0, 0];

        if (origin) {
            // Translate to origin
            m[4] -= origin[0];
            m[5] -= origin[1];
        }

        matrix.scale(m, m, scale);

        if (rotation) {
            matrix.rotate(m, m, rotation);
        }

        if (origin) {
            // Translate back from origin
            m[4] += origin[0];
            m[5] += origin[1];
        }

        m[4] += position[0];
        m[5] += position[1];
        return m;
    };

    var _default = Transformable;
    module.exports = _default;


}